﻿using SlimDX;
using SlimDX.DirectInput;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Timers;
using System.Windows.Forms;



/********************
 * 
 * 海康的dll用的32位版本，不能用64版本
 * 
 * 
 * 
 * ********************/
/****************************
 *             一些疑惑
 * 
 * Setting里的设置，举个例子：文件存储路径
 * 保存了设置，关闭之后下次打开已经是设置好的
 * 
 * *************************/
namespace HCROV
{
    public partial class HCMainForm : Form
    {
        //摄像机参数
        private uint iLastErr = 0;
        private Int32 m_lUserID = -1;
        private bool m_bInitSDK = false;
        private bool m_bRecord = false;
        private bool m_bTalk = false;
        private Int32 m_lRealHandle = -1;
        private int lVoiceComHandle = -1;


        private string str;
        int i;
        bool LogFlag=false; //是否成功登录

        CHCNetSDK.REALDATACALLBACK RealData = null;
        public CHCNetSDK.NET_DVR_PTZPOS m_struPtzCfg;


        public delegate float GetData();//获取Protocol类中暂时存储的Pitch等值
        public delegate void SendDatas(byte[] data);//将byte数组发送到Protocol类中暂时存储
        public delegate void SendNum(int data);//将数值发送到Protocol中转化并暂存储
        public delegate int getTrackbarValue(TrackBar tb);
        private delegate void setTrbValue(TrackBar tb,int i);
        public delegate void SetBtnText(System.Windows.Forms.Button button, string Text);
        public delegate byte[] SendBytes();

        private bool KeyFlag = false; //使能按键标志位
        private Thread refreshData;//数据更新
        private Thread joyscan;//手柄扫描

        GetData getpitch = new GetData(szyProtocol.sendpitch);
        GetData getroll = new GetData(szyProtocol.sendroll);
        GetData getyaw = new GetData(szyProtocol.sendyaw);
        GetData getdepth = new GetData(szyProtocol.senddepth);
        GetData getelec = new GetData(szyProtocol.sendelec);

        //已经换在另外一个类里面，是否去掉要再检查
        //SendDatas senddatas = new SendDatas(szyProtocol.getbytes);
        SendBytes sendbytes = new SendBytes(szyProtocol.MoveControlData);

        SendNum sendForward = new SendNum(szyProtocol.getForwardThrottle);
        SendNum sendTransverse = new SendNum(szyProtocol.getTransverseThrottle);
        SendNum sendVertical = new SendNum(szyProtocol.getVerticalThrottle);
        SendNum sendLight = new SendNum(szyProtocol.getLightPWM);
        SendNum sendSteering = new SendNum(szyProtocol.getSteering);
        SendNum sendPtz = new SendNum(szyProtocol.getPTZ);


        /// <summary>
        /// 跨线程改变按键的文本信息
        /// </summary>
        /// <param name="button"></param>
        /// <param name="txt"></param>
        void SetButtonText(System.Windows.Forms.Button button, string txt)
        {
            if (button.InvokeRequired)
            {
                // 多线程调用时，通过主线程去访问
                SetBtnText setBtnText = SetButtonText;
                this.Invoke(setBtnText, button, txt);
            }
            else
            {
                button.Text = txt; // 主线程调用时，直接赋值
            }
        }


        private void setThrottle(TrackBar trb,int i)
        {
            if (i == 1)
            {
                if (trb.Value < 4)
                    trb.Value += 1;
            }
            if (i == -1)
            {
                if (trb.Value > 0)
                    trb.Value -= 1;
            }
        }
        
        private void setTrackbarValue(TrackBar trb,int i)
        {
            if (trb.InvokeRequired)
            {
                setTrbValue sb = new setTrbValue(setThrottle);
                this.Invoke(sb, new object[] { trb,i });
            }
            else
            {
                trb.Value += i;
            }
        }

        private int getTrbValue(TrackBar trb)
        {
            if (trb.InvokeRequired)
            {
                return (int)trb.Invoke(new getTrackbarValue(getTrbValue), trb);
            }
            else
            {
                return trb.Value;
            }
        }

        public HCMainForm()
        {
            InitializeComponent();
            lblDateTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

            m_bInitSDK = CHCNetSDK.NET_DVR_Init();
            if (m_bInitSDK == false)
            {
                MessageBox.Show("NET_DVR_Init error!");
                return;
            }
            else
            {
                //保存SDK日志 To save the SDK log
                CHCNetSDK.NET_DVR_SetLogToFile(3, Properties.Settings.Default.SdkFloder, true);
            }

        }

        [DllImport("user32.dll")]
        public static extern bool ReleaseCapture();
        [DllImport("user32.dll")]
        public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);



        /// <summary>
        /// 清理所有正在使用的资源。
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (m_lRealHandle >= 0)
            {
                CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle);
            }
            if (m_lUserID >= 0)
            {
                CHCNetSDK.NET_DVR_Logout(m_lUserID);
            }
            if (m_bInitSDK == true)
            {
                CHCNetSDK.NET_DVR_Cleanup();
            }
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        /// <summary>
        /// 摄像机登录方法
        /// </summary>
        private void camera_Login()
        {
            if (textBoxIP.Text == "" || textBoxPort.Text == ""  )
            {
                MessageBox.Show("Please input IP, Port, User name and Password!");
                LogFlag = false;
                return;
            }
            if (m_lUserID < 0)
            {
                string DVRIPAddress = textBoxIP.Text; //设备IP地址或者域名
                Int16 DVRPortNumber = Int16.Parse(textBoxPort.Text);//设备服务端口号
                string DVRUserName = "admin";//设备登录用户名
                string DVRPassword = "HQ0401204012";//设备登录密码

                CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo = new CHCNetSDK.NET_DVR_DEVICEINFO_V30();

                //登录设备 Login the device
                m_lUserID = CHCNetSDK.NET_DVR_Login_V30(DVRIPAddress, DVRPortNumber, DVRUserName, DVRPassword, ref DeviceInfo);
                if (m_lUserID < 0)
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    str = "NET_DVR_Login_V30 failed, error code= " + iLastErr; //登录失败，输出错误号
                    MessageBox.Show(str);
                    LogFlag = false;
                    return;
                }
                else
                {
                    //登录成功
                    MessageBox.Show("Login Success!");
                    LogFlag = true;
                    VideoShow();
                    btnLogin.Text = "Logout";
                }

            }
            else
            {
                //注销登录 Logout the device
                if (m_lRealHandle >= 0)
                {
                   
                    MessageBox.Show("Please stop live view firstly");
                    LogFlag = true;
                    return;
                }

                if (!CHCNetSDK.NET_DVR_Logout(m_lUserID))
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    str = "NET_DVR_Logout failed, error code= " + iLastErr;
                    MessageBox.Show(str);
                    LogFlag = true;
                    return;
                }
                m_lUserID = -1;
                btnLogin.Text = "Login";
                LogFlag = false;
            }
            return;
        }

        private void BtnJPEG_Click(object sender, EventArgs e)
        {
            takePhoto();
        }

        /// <summary>
        /// 截图方法
        /// </summary>
        public void takePhoto()
        {
            string sJpegPicFileName;
            //图片保存路径和文件名 the path and file name to save
            sJpegPicFileName = Properties.Settings.Default.PhotoFloder+ "\\" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss") + ".jpg";

            int lChannel = 1; //通道号 Channel number

            CHCNetSDK.NET_DVR_JPEGPARA lpJpegPara = new CHCNetSDK.NET_DVR_JPEGPARA();

            /*


             图像质量调节
             具体参数查看SDK说明


             */
            lpJpegPara.wPicQuality = 0; //图像质量 Image quality


            lpJpegPara.wPicSize = 0xff; //抓图分辨率 Picture size: 2- 4CIF，0xff- Auto(使用当前码流分辨率)，抓图分辨率需要设备支持，更多取值请参考SDK文档

            //JPEG抓图 Capture a JPEG picture
            if (!CHCNetSDK.NET_DVR_CaptureJPEGPicture(m_lUserID, lChannel, ref lpJpegPara, sJpegPicFileName))
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_CaptureJPEGPicture failed, error code= " + iLastErr;
                MessageBox.Show(str);
                return;
            }
            else
            {
                str = "Successful to capture the JPEG file and the saved file is " + sJpegPicFileName;
                MessageBox.Show(str);
            }
            return;

            
        }

        /// <summary>
        /// 录像方法
        /// </summary>
        public void Record()
        {
            //录像保存路径和文件名 the path and file name to save
            string sVideoFileName;
            sVideoFileName = Properties.Settings.Default.VideoFloder +"\\"+ DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss") + ".mp4";

            if (m_bRecord == false)
            {
                //强制I帧 Make a I frame
                int lChannel = 1; //通道号 Channel number
                CHCNetSDK.NET_DVR_MakeKeyFrame(m_lUserID, lChannel);

                //开始录像 Start recording
                if (!CHCNetSDK.NET_DVR_SaveRealData(m_lRealHandle, sVideoFileName))
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    str = "NET_DVR_SaveRealData failed, error code= " + iLastErr;
                    MessageBox.Show(str);
                    return;
                }
                else
                {
                    btnRecord.Text = "Stop Record";
                    m_bRecord = true;
                }
            }
            else
            {
                //停止录像 Stop recording
                if (!CHCNetSDK.NET_DVR_StopSaveRealData(m_lRealHandle))
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    str = "NET_DVR_StopSaveRealData failed, error code= " + iLastErr;
                    MessageBox.Show(str);
                    return;
                }
                else
                {
                    str = "Successful to stop recording and the saved file is " + sVideoFileName;
                    MessageBox.Show(str);
                    btnRecord.Text = "Start Record";
                    m_bRecord = false;
                }
            }

            return;
        }
        private void BtnRecord_Click(object sender, EventArgs e)
        {
            if (btnRecord.Text == "Stop Record")
                btnRecord.BackColor = Color.White;
            Record();
            btnRecord.BackColor = Color.Red;
        }
        private void Btn_Exit_Click(object sender, EventArgs e)
        {
            //停止预览 Stop live view 
            if (m_lRealHandle >= 0)
            {
                CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle);
                m_lRealHandle = -1;
            }

            //注销登录 Logout the device
            if (m_lUserID >= 0)
            {
                CHCNetSDK.NET_DVR_Logout(m_lUserID);
                m_lUserID = -1;
            }

            CHCNetSDK.NET_DVR_Cleanup();
            //断开Socket
            hcConnect.dispose(socket);
            //Application.Exit();
        }

        private void BtnLogin_Click(object sender, EventArgs e)
        {
            if (LogFlag) VideoShow();
            camera_Login();
            //ConnectROV();//不连接机器人时注释掉
        }

        #region Code By Suzeyu

        #region  文件操作
        /// <summary>
        /// 判断文件夹是否存在
        /// </summary>
        /// <param name="dir">需要检查的文件路径</param>
        /// <returns></returns>
        private bool FolderExists(string dir)
        {
            try
            {
                DirectoryInfo dirInfo = new DirectoryInfo(dir);
                if (dirInfo.Exists) { return true; }
                else { return false; }
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 选择文件夹并创建子目录
        /// </summary>
        private void CreateFloder()
        {
            if (FileLocation.ShowDialog() == DialogResult.OK)
            {
                lblFileLocation.Text = FileLocation.SelectedPath;
                Properties.Settings.Default.SaveFileLocation = FileLocation.SelectedPath;
                Properties.Settings.Default.Save();
            }
            if (FolderExists(lblFileLocation.Text + "\\Photo") && FolderExists(lblFileLocation.Text + "\\SdkLog") && FolderExists(lblFileLocation.Text + "\\VIdeo"))
            {

            }
            else
            {
                //子文件夹不存在，新建子文件夹
                string PathPhoto = Properties.Settings.Default.SaveFileLocation + "\\Photo";
                string PathVideo = Properties.Settings.Default.SaveFileLocation + "\\Video";
                string PathSdkLog = Properties.Settings.Default.SaveFileLocation + "\\SdkLog";
                Directory.CreateDirectory(PathPhoto);
                Directory.CreateDirectory(PathVideo);
                Directory.CreateDirectory(PathSdkLog);
                Properties.Settings.Default.PhotoFloder = PathPhoto;
                Properties.Settings.Default.VideoFloder = PathVideo;
                Properties.Settings.Default.SdkFloder = PathSdkLog;
            }
            MessageBox.Show("已选择文件夹，子文件夹已建立");
        }


        #endregion

        #region  模拟延时
        uint delay_nms = 60;
        [DllImport("kernel32.dll")]
        static extern uint GetTickCount();
        static void Delay(uint ms)
        {
            uint start = GetTickCount();
            while (GetTickCount() - start < ms)
            {
                Application.DoEvents();
            }
        }
        #endregion

        #region  视频
        /// <summary>
        /// 打开视频
        /// </summary>
        private void VideoShow()
        {
            if (m_lUserID < 0)
            {
                MessageBox.Show("Please login the device firstly");
                return;
            }

            if (m_lRealHandle < 0)
            {
                CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
                lpPreviewInfo.hPlayWnd = RealPlayWnd.Handle;//预览窗口
                lpPreviewInfo.lChannel = 1;//预te览的设备通道
                lpPreviewInfo.dwStreamType = 0;//码流类型：0-主码流，1-子码流，2-码流3，3-码流4，以此类推
                lpPreviewInfo.dwLinkMode = 0;//连接方式：0- TCP方式，1- UDP方式，2- 多播方式，3- RTP方式，4-RTP/RTSP，5-RSTP/HTTP 
                lpPreviewInfo.bBlocked = true; //0- 非阻塞取流，1- 阻塞取流
                lpPreviewInfo.dwDisplayBufNum = 1; //播放库播放缓冲区最大缓冲帧数
                lpPreviewInfo.byProtoType = 0;
                lpPreviewInfo.byPreviewMode = 0;

                if (RealData == null)
                {
                    RealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);//预览实时流回调函数
                }

                IntPtr pUser = new IntPtr();//用户数据

                //打开预览 Start live view 
                m_lRealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, null/*RealData*/, pUser); //V30也可以看视频，但是V30的延时高
                if (m_lRealHandle < 0)
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    str = "NET_DVR_RealPlay_V40 failed, error code= " + iLastErr; //预览失败，输出错误号
                    MessageBox.Show(str);
                    return;
                }
                else
                {
                    
                    //预览成功
                    
                    RealPlayWnd.BackgroundImage = null;
                }
            }
            else
            {
                //停止预览 Stop live view 
                if (!CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle))
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    str = "NET_DVR_StopRealPlay failed, error code= " + iLastErr;
                    MessageBox.Show(str);
                    return;
                }
                m_lRealHandle = -1;
                
                RealPlayWnd.BackgroundImage = Properties.Resources.无背景LOGO1;
            }
            return;
        }

        public void RealDataCallBack(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser)
        {
            if (dwBufSize > 0)
            {
                byte[] sData = new byte[dwBufSize];
                Marshal.Copy(pBuffer, sData, 0, (Int32)dwBufSize);

                string str = "实时流数据.ps";
                FileStream fs = new FileStream(str, FileMode.Create);
                int iLen = (int)dwBufSize;
                fs.Write(sData, 0, iLen);
                fs.Close();
            }
        }
        #endregion

        #region Socket有关

        HCConnect hcConnect = new HCConnect();

        public static Socket socket;


        /// <summary>
        /// 连接ROV
        /// </summary>
        private void ConnectROV()
        {

            if (btnConnectTest.Text == "断开连接")
            {
                hcConnect.dispose(socket);
                TBCtrlIP.ReadOnly = false;
                TBCtrlPort.ReadOnly = false;
                textBoxIP.ReadOnly = false;
                textBoxPort.ReadOnly = false;
                btnConnectTest.Text = "连接";
                KeyFlag = false;
                refreshData.Abort();
                joyscan.Abort();
            }
            else
            {
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                hcConnect.Connect(TBCtrlIP.Text, TBCtrlPort.Text, socket);
                Delay(100);
                if (hcConnect.IsConnect(socket))
                {
                    TBCtrlIP.ReadOnly = true;
                    TBCtrlPort.ReadOnly = true;
                    textBoxIP.ReadOnly = true;
                    textBoxPort.ReadOnly = true;
                    btnConnectTest.Text = "断开连接";

                    //记录上一次输入的IP地址和端口
                    Properties.Settings.Default.ControlIP = TBCtrlIP.Text;
                    Properties.Settings.Default.ControlPort = TBCtrlPort.Text;
                    Properties.Settings.Default.Save();

                    //Delay(1000);//必须先延时一会等socket成功连接上
                    hcConnect.Receive(socket);
                    refreshData = new Thread(RefreshLBL);
                    KeyFlag = true;
                    refreshData.Start();
                }
            }
        }

        /// <summary>
        /// 更新label的数值显示
        /// </summary>
        private void RefreshLBL()
        {
            txtRecive.BeginInvoke(new Action(() => { txtRecive.AppendText("数据更新初始化成功...\n"); }));
            while (true)
            {
                //(暂行)新开一个线程在里面进行数据的获取显示

                Delay(30);//线程任务简单而运算速度快，过快更新UI会致使UI线程卡死
                lblPitch.BeginInvoke(new Action(() => { lblPitch.Text = getroll().ToString(); }));
                lblRoll.BeginInvoke(new Action(() => { lblRoll.Text = getpitch().ToString(); }));
                lblYaw.BeginInvoke(new Action(() => { lblYaw.Text = getyaw().ToString(); }));
                lblDepth.BeginInvoke(new Action(() => { lblDepth.Text = getdepth().ToString(); }));
                lblSteer.BeginInvoke(new Action(() => { lblSteer.Text = getelec().ToString(); }));
                lblDateTime.BeginInvoke(new Action(() => { lblDateTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); }));
            }
        }

        private void BtnConnectTest_Click(object sender, EventArgs e)
        {
            joyscan = new Thread(new ThreadStart(JoyScan));
            ConnectROV();//开发阶段测试使用
            joyscan.Start();
        }


        #endregion


        #region 按键控制
        private void HCMainForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (KeyFlag)
            {
                string keyvalue = e.KeyData.ToString();
                try
                {
                    switch (keyvalue)
                    {
                        //换挡
                        case "D1":
                            if (trbVelocity.Value > 0)
                                trbVelocity.Value -= 1;
                            break;
                        case "D2":
                            if (trbVelocity.Value < 4)
                                trbVelocity.Value += 1;
                            break;
                        case "D3":
                            trbLightPWM.Value -= 50;
                            break;
                        case "D4":
                            trbLightPWM.Value += 50;
                            break;
                        case "D5":
                            Steering(1);//二档是中等速度
                            hcConnect.sendByteData(socket, sendbytes());
                            break;
                        case "D6":
                            Steering(-1);
                            hcConnect.sendByteData(socket, sendbytes());
                            break;

                        //运动
                        case "W":    //向前运动  
                            ForwardThrottle(-100);
                            TransverseThrottle(100);
                            hcConnect.sendByteData(socket, sendbytes());
                            break;
                        case "S":    //向后运动  
                            ForwardThrottle(100);
                            TransverseThrottle(-100);
                            hcConnect.sendByteData(socket, sendbytes());
                            break;
                        case "A":    //向左转动   
                            ForwardThrottle(100);
                            TransverseThrottle(100);
                            hcConnect.sendByteData(socket, sendbytes());
                            break;
                        case "D":    //向右转动  
                            ForwardThrottle(-100);
                            TransverseThrottle(-100);
                            hcConnect.sendByteData(socket, sendbytes());
                            break;
                        case "L":
                            sendPtz(1);
                            break;
                        case "K":
                            sendPtz(0);
                            break;
                        case "Up":
                            VerticalThorttle(100);
                            hcConnect.sendByteData(socket, sendbytes());
                            break;
                        case "Down":
                            VerticalThorttle(-100);
                            hcConnect.sendByteData(socket, sendbytes());
                            break;
                        case "I":
                            if (szyProtocol.LightPwm == 0)
                                LightPWM(trbLightPWM.Value + 1000);
                            else
                                LightPWM(0);
                            hcConnect.sendByteData(socket, sendbytes());
                            break;
                        default:
                            e.Handled = true;//屏蔽其他热键
                            break;
                    }
                }
                catch
                { }
            }
        }



        private void HCMainForm_KeyUp(object sender, KeyEventArgs e)
        {
            if (KeyFlag)
            {
                ForwardThrottle(0);
                TransverseThrottle(0);
                VerticalThorttle(0);
                hcConnect.sendByteData(socket,sendbytes());
            }
        }

        #endregion


        #region 手柄控制
        /**********************************************************************
        * ------  You  Need  To  Know  -------
        * 本程序中要实现手柄控制需要第三方包SlimDX的支持(已加入程序之中)
        * 也可以使用微软官方的DirectInput库，但是本人尝试过两次没有成功，就转而使用第三方库来获取手柄
        * 虽然MSDN已经不推荐用DirectInput了 有关资料可以看https://blog.csdn.net/icdbow/article/details/6741084
        * 本程序适配的手柄为------北通阿修罗(14年款)，其他品牌型号的手柄需要自行更改程序调试
        * 
        * ---------  手柄按键对应  ----------
        * X、Y对应主摇杆坐标
        * x>0 推杆向右 x<0推杆向左     (-100<x<100)
        * y>0 推杆向下 y<0推杆向上     (-100<y<100)
        * 
        * z对应LT、RT
        * z>0  ->  LT                (-100<z<100)
        * z<0  ->  RT
        * 
        * Rotation对应副摇杆
        * 
        * 
        * GetPointOfViewControllers对应坐下按键盘
        * 一共八方向，本程序只用了四方向
        * 顺时针方向(0,9000,18000,27000)四个值分别对应四个键位
        * 
        * 按键GetButtons
        * 按键0=A
        * 按键1=B
        * 按键2=X
        * 按键3=Y
        * 按键4=LB
        * 按键5=RB
        * 按键6=BACK
        * 按键7=START
        * 按键8=主摇杆按键
        * 按键9=副摇杆按键
        * 
        ***********************************************************************/
        DirectInput input = new DirectInput();
        Joystick stick;
        Joystick[] Joysticks;
        JoystickState state = new JoystickState();



        /// <summary>
        /// 获取并初始化手柄
        /// </summary>
        /// <returns></returns>
        public Joystick[] GetJoysticks()
        {
            Console.WriteLine("GetJoyStick");
            List<Joystick> joysticks = new List<Joystick>();
            foreach (var device in input.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly))
            {
                try
                {
                    stick = new Joystick(input, device.InstanceGuid);
                    stick.Acquire();
                    foreach (var deviceObject in stick.GetObjects())
                    {
                        if ((deviceObject.ObjectType & ObjectDeviceType.Axis) != 0)
                        {
                            stick.GetObjectPropertiesById((int)deviceObject.ObjectType).SetRange(-100, 100);
                        }
                    }
                    joysticks.Add(stick);
                }
                catch (DirectInputException)
                {

                }
            }
            return joysticks.ToArray();
        }


        int x_Left, y_Left; //左边主摇杆
        int x_Right, y_Right;//右边副摇杆
        int Z_Top, FordThrottle, turnThrottle;//顶部遥感和两个油门值



        //采用定时器定时查询的方法读取手柄按键 150ms查询一次
        private void JoyScan()
        {
            System.Timers.Timer timer = new System.Timers.Timer();
            timer.Interval = 110;
            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
            timer.Start();
        }

        private void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            for (int i = 0; i < Joysticks.Length; i++)
            {
                stickHandle(Joysticks[i]);
            }
        }


        #region 手柄扫描函数

        private void stickHandle(Joystick stick)
        {
            Console.WriteLine("JoyCheck");
            state = stick.GetCurrentState();
            int[] POV = state.GetPointOfViewControllers();
            bool[] buttons = state.GetButtons();
            x_Left = state.X;
            y_Left = state.Y;
            y_Right = state.RotationY;
            Z_Top = state.Z;

            //测试用
            Console.WriteLine(x_Left);
            Console.WriteLine(y_Left);
            Console.WriteLine(y_Right);
            Console.WriteLine(Z_Top);

            if (y_Left < -40 || y_Left > 40)//消抖
            {
                FordThrottle = y_Left;
            }
            else
            {
                FordThrottle = 0;
            }

            if (x_Left < -40 || x_Left > 40)//消抖
            {
                turnThrottle = x_Left;
            }
            else
            {
                turnThrottle = 0;
            }

            ForwardThrottle(FordThrottle - turnThrottle);//左电机
            TransverseThrottle(-FordThrottle - turnThrottle);//右电机
            if (y_Right < -40 || y_Right > 40)//消抖
            {
                VerticalThorttle(y_Right);
                //sendByteData(sendbyte());
            }
            else
            {
                VerticalThorttle(0);
                //sendByteData(sendbyte());
            }

            if (Z_Top < -30)//  给满了600的PWM  危险操作
            {
                Steering(1);
                //sendByteData(sendbyte());
            }
            else if (Z_Top > 30)//  给满了600的PWM  危险操作
            {
                Steering(-1);
                //sendByteData(sendbyte());
            }
            else
            {
                Steering(0);
                //sendByteData(sendbyte());
            }
            hcConnect.sendByteData(socket, sendbytes());


            if (buttons[0])
            {
                sendPtz(1);
                hcConnect.sendByteData(socket, sendbytes());
                //Console.WriteLine(save_KeyVaule);
            }
            if (buttons[1])
            {
                sendPtz(0);
                hcConnect.sendByteData(socket, sendbytes());
                //Console.WriteLine(save_KeyVaule);
            }

            if (buttons[3])
            {
                Steering(2);
                hcConnect.sendByteData(socket, sendbytes());

            }
            if (buttons[4])
            {
                setTrackbarValue(trbVelocity,-1);
                hcConnect.sendByteData(socket,sendbytes());
            }
            if (buttons[5])
            {
                setTrackbarValue(trbVelocity,1);
                hcConnect.sendByteData(socket,sendbytes());
            }

            if (buttons[7])
            {
                if (szyProtocol.LightPwm == 0)
                    LightPWM(getTrbValue(trbLightPWM) + 1000);
                else
                    LightPWM(0);
                hcConnect.sendByteData(socket, sendbytes());
            }
            //if (POV[0] == 0)//左下按键，顺时针方向四个值分别对应四个键位
            //{

            //    //Console.WriteLine(save_KeyVaule);
            //}
            //if (POV[0] == 9000)
            //{

            //    //Console.WriteLine(save_KeyVaule);
            //}
            //if (POV[0] == 18000)
            //{

            //    //Console.WriteLine(save_KeyVaule);
            //}
            //if (POV[0] == 27000)
            //{
            //    //Console.WriteLine(save_KeyVaule);
            //}

            
            //if (buttons[2])
            //    textBox1.AppendText("2\n");

            //if (buttons[6])
            //{ }

            
            //if (buttons[8])
            //{
            //}
            //if (buttons[9]) 
            //textBox1.AppendText("9\n");

            //注释掉暂时没用到的按键，需要时再取消注释，避免更加延时
        }

        #endregion
        #endregion

        #region 指令数值传送

        private void ForwardThrottle(int throttle)  //左电机
        {
            sendForward(1500 + throttle * getTrbValue(trbVelocity));
        }

        private void TransverseThrottle(int throttle)//右电机
        {
            sendTransverse(1500 + throttle * getTrbValue(trbVelocity));
        }

        private void VerticalThorttle(int throttle)
        {
            sendVertical(throttle * getTrbValue(trbVelocity));
        }

        private void LightPWM(int throttle)
        {
            sendLight(throttle);
        }

        private void Steering(int throttle)
        {
            //舵机采用指令式，不能转速过快或者抖动太剧烈
            //设定速度档位
            //在下位机做响应，上位机只做发送速度指令
            sendSteering(throttle);

        }


        #endregion

        /// <summary>
        /// 选定视频文件保存路径
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnPickFileLocation_Click(object sender, EventArgs e)
        {
            CreateFloder();
        }


        #region  窗口移动函数

        bool beginMove = false;//初始化鼠标位置
        int currentXPosition;
        int currentYPosition;
        private void HCMainForm_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                beginMove = true;
                currentXPosition = MousePosition.X;//鼠标的x坐标为当前窗体左上角x坐标
                currentYPosition = MousePosition.Y;//鼠标的y坐标为当前窗体左上角y坐标
            }
        }

        private void HCMainForm_MouseMove(object sender, MouseEventArgs e)
        {
            if (beginMove)
            {
                this.Left += MousePosition.X - currentXPosition;//根据鼠标x坐标确定窗体的左边坐标x
                this.Top += MousePosition.Y - currentYPosition;//根据鼠标的y坐标窗体的顶部，即Y坐标
                currentXPosition = MousePosition.X;
                currentYPosition = MousePosition.Y;
            }
        }

        private void HCMainForm_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                currentXPosition = 0; //设置初始状态
                currentYPosition = 0;
                beginMove = false;
            }
        }

        private void Button3_Click(object sender, EventArgs e)
        {
            this.Close();   
        }

        private void Button4_Click(object sender, EventArgs e)
        {
            
            if (WindowState == FormWindowState.Maximized)
                WindowState = FormWindowState.Normal;
            else
                this.WindowState = FormWindowState.Maximized;
        }

        private void BtnMin_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private void Panel2_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                beginMove = true;
                currentXPosition = MousePosition.X;//鼠标的x坐标为当前窗体左上角x坐标
                currentYPosition = MousePosition.Y;//鼠标的y坐标为当前窗体左上角y坐标
            }
        }

        private void Panel2_MouseMove(object sender, MouseEventArgs e)
        {
            if (beginMove)
            {
                this.Left += MousePosition.X - currentXPosition;//根据鼠标x坐标确定窗体的左边坐标x
                this.Top += MousePosition.Y - currentYPosition;//根据鼠标的y坐标窗体的顶部，即Y坐标
                currentXPosition = MousePosition.X;
                currentYPosition = MousePosition.Y;
            }
        }

        private void Panel2_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                currentXPosition = 0; //设置初始状态
                currentYPosition = 0;
                beginMove = false;
            }
        }

 


        private void Panel2_DoubleClick(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Maximized)
                WindowState = FormWindowState.Normal;
            else
                this.WindowState = FormWindowState.Maximized;
        }
        #endregion

        private void Button1_Click(object sender, EventArgs e)
        {
            if (hcConnect.IsConnect(socket))
                MessageBox.Show("Connect");
        }
        private void Button2_Click(object sender, EventArgs e)
        {
            GetJoysticks();
            Joysticks = GetJoysticks();
            Thread joythread = new Thread(new ThreadStart(JoyScan));
            //JoyScan();
            joythread.Start();
        }

        #endregion

    }
}
